/*
 * Copyright 2009 BioTeam Inc
 * 
 * Licensed under License GNU LESSER GENERAL PUBLIC LICENSE version 3.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.gnu.org/copyleft/lesser.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package net.bioteam.appweb.acd;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.bioteam.appweb.model.Code;
import net.bioteam.appweb.model.Comment;
import net.bioteam.appweb.model.Ctrl;
import net.bioteam.appweb.model.Paragraph;
import net.bioteam.appweb.model.Parameter;
import net.bioteam.appweb.model.ParameterType;
import net.bioteam.appweb.model.Program;
import net.bioteam.appweb.model.Value;
import net.bioteam.appweb.model.Vlist;

import org.antlr.runtime.ANTLRInputStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.tree.CommonTree;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class AcdToProgram
{

	public static String EMBOSS_DATA = "/opt/emboss/share/EMBOSS/data";
	public static String EMBOSS_ACD = "/opt/emboss/share/EMBOSS/acd";
	public final static Log logger = LogFactory.getLog(AcdToProgram.class);
	static Map<String, String> codes;
	static Map<String, String> codons;
	static Map<String, String> protein_matrices;
	static Map<String, String> DNA_matrices;
	static Map<String, String> proteinstructure_matrices;

	public static Program toProgram(String name) throws Exception
	{
		File acdfile = new File(EMBOSS_ACD + File.separator + name + ".acd");
		File datadir=new File(EMBOSS_DATA);
		if (!acdfile.exists()|| !datadir.exists() || !datadir.isDirectory())
			return null;
		ANTLRInputStream input = new ANTLRInputStream(new FileInputStream(acdfile));
		AcdLexer lexer = new AcdLexer(input);
		CommonTokenStream tokens = new CommonTokenStream(lexer);
		AcdParser parser = new AcdParser(tokens);
		AcdParser.program_return ret = parser.program();
		// program tree
		CommonTree tree = (CommonTree) ret.getTree();
		Program program = new Program();

		// a auto parameter
		Parameter p = new Parameter();
		p.setName("global_auto");
		p.setHidden(true);
		p.setType(ParameterType.StringType);
		p.setGroup(1);
		Code format = new Code();
		format.setLanguage("javascript");
		format.setCode(" \" -auto -stdout\"");
		p.setFormat(format);
		program.get_Parameters().add(p);

		int group = 0;
		for (int i = 0; i < tree.getChildCount(); i++)
		{
			CommonTree child = (CommonTree) tree.getChild(i);
			switch (child.getType())
			{
			case AcdLexer.PARAMETER:
				if (child.getChild(0).getText().equals("application"))
				{
					setHead(program, child);
				} else
				{

					group = toParameter(child, group, program);
				}
				break;
			case AcdLexer.SECTION:
				group = toParagraph(child, group, program);
				break;
			default:
				break;
			}
		}
		p = new Parameter();
		p.setName("global_results");
		p.setHidden(true);
		p.setType(ParameterType.ResultsType);
		p.setFilenames("outfile*");
		p.setGroup(100);
		program.get_Parameters().add(p);

		program.setLastmodified(acdfile.lastModified());
		program.setAcd(true);
		program.setFile(acdfile.getAbsolutePath());
		
		return program;
	}

	protected static int toParagraph(CommonTree tree, int group, Object parent)
	{
		Paragraph paragraph = new Paragraph();
		paragraph.setType(ParameterType.ParagraphType);
		paragraph.setName(tree.getChild(0).getText());
		Map<String, String> attributes = collectAttributes(tree);
		paragraph.setPrompt(attributes.get("information"));
		if (parent instanceof Program)
		{
			((Program) parent).get_Parameters().add(paragraph);
		} else
		{
			((Paragraph) parent).get_Parameters().add(paragraph);
		}

		for (int i = 0; i < tree.getChildCount(); i++)
		{
			CommonTree child = (CommonTree) tree.getChild(i);
			if (child.getType() == AcdLexer.PARAMETER)
			{
				group = toParameter(child, group, paragraph);
			} else if (child.getType() == AcdLexer.SECTION)
			{
				group = toParagraph(child, group, paragraph);
			}
		}
		return group;
	}

	protected static void setHead(Program program, CommonTree parameter)
	{
		// set application name.
		program.setName(parameter.getChild(1).getText());
		program.setCommand(program.getName());
		program.setTitle(parameter.getChild(1).getText());
		program.setAuthors("Tim Carver");
		program.setReference("http://emboss.sourceforge.net");
		program.setDoclink("http://emboss.sourceforge.net");
		Map<String, String> attributes = collectAttributes(parameter);

		if (attributes.containsKey("documentation"))
		{
			program.setDescription(attributes.get("documentation"));
		} else
		{
			program.setDescription(" No Description");
		}
		if (attributes.containsKey("groups"))
		{
			//logic to remove artifical groups.
			String groups[]=attributes.get("groups").split(":");
			String group=groups[0];
			groups=group.split(",");
			group=groups[0];
			group=group.substring(0, 1).toUpperCase()+group.substring(1).toLowerCase();
			if (group.equals("Hmm"))
			{
				program.getCategory().add("HMMER");
			} else if (group.equals("Phylogeny"))
			{
				program.getCategory().add("Phylip");
			} else
			{
				program.getCategory().add("Emboss_"+group);
			}
		}
	}

	protected static int toParameter(CommonTree tree, int group, Object parent)
	{
		String type = tree.getChild(0).getText();
		String name = tree.getChild(1).getText();
		Parameter p = new Parameter();
		if (isReserverdWord(name))
		{
			p.setName(name + "1");
		} else
		{
			p.setName(name);
		}

		group += 5;
		p.setGroup(group);

		Map<String, String> attributes = processGlobalAttributes(p, tree);
		Comment comment = p.getComment();
		if (comment == null)
		{
			comment = new Comment();
			p.setComment(comment);
		}
		if (type.equals("boolean") || type.equals("toggle"))
		{
			p.setType(ParameterType.BooleanType);
			// special hanlding for default value
			if (p.getVdef() != null)
			{
				if (p.getVdef().getValue().equals("Y"))
				{
					p.getVdef().setValue("1");
				} else
				{
					p.getVdef().setValue("0");
				}
			} else
			{
				Value vdef = new Value();
				vdef.setValue("0");
				p.setVdef(vdef);
			}
			// special handling for code
			// http://www.howtocreate.co.uk/xor.html
			String code = "(value != vdef)?(vdef==1?\" -no" + name + "\": \" -" + name + "\"):\"\"";
			p.getFormat().setCode(code);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("float"))
		{
			p.setType(ParameterType.FloatType);
			if (attributes.containsKey("minimum") && isLiteralValue(attributes.get("minimum")))
			{
				Value min = new Value();
				min.setValue(attributes.get("minimum"));
				p.setScalemin(min);
				comment.getValue().add("The minimum value is " + attributes.get("minimum"));
			}
			if (attributes.containsKey("maximum") && isLiteralValue(attributes.get("maximum")))
			{
				Value max = new Value();
				max.setValue(attributes.get("maximum"));
				p.setScalemax(max);
				comment.getValue().add("The maximum value is " + attributes.get("maximum"));
			}

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("integer"))
		{
			p.setType(ParameterType.IntegerType);
			if (attributes.containsKey("minimum") && isLiteralValue(attributes.get("minimum")))
			{
				Value min = new Value();
				min.setValue(attributes.get("minimum"));
				p.setScalemin(min);
				comment.getValue().add("The minimum value is " + attributes.get("minimum"));
			}

			if (attributes.containsKey("maximum") && isLiteralValue(attributes.get("maximum")))
			{
				Value max = new Value();
				max.setValue(attributes.get("maximum"));
				p.setScalemax(max);
				comment.getValue().add("The maximum value is " + attributes.get("maximum"));
			}

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("string"))
		{
			p.setType(ParameterType.StringType);
			if (attributes.containsKey("minlength"))
			{
				comment.getValue().add("value must has at minimum " + attributes.get("minlength") + " characters");
				Ctrl ctrl = new Ctrl();
				ctrl.setMessage("value must has at minimum " + attributes.get("minlength") + " characters");
				
				ctrl.setLanguage("javascript");
				ctrl.setCode("value.length>=" + attributes.get("minlength"));
				
				p.getCtrls().add(ctrl);
			}
			if (attributes.containsKey("maxlength"))
			{
				comment.getValue().add("value must has at maximum " + attributes.get("maxlength") + " characters");
				Ctrl ctrl = new Ctrl();
				ctrl.setMessage("value must has at maximum " + attributes.get("maxlength") + " characters");
				
				ctrl.setLanguage("javascript");
				ctrl.setCode("value.length<=" + attributes.get("maxlength"));
				p.getCtrls().add(ctrl);
			}
			if (attributes.containsKey("word") && attributes.get("word").toUpperCase().equals("Y"))
			{
				comment.getValue().add("String can not have space character");
				Ctrl ctrl = new Ctrl();
				ctrl.setMessage("String can not have space character");
				ctrl.setLanguage("javascript");
				ctrl.setCode("value.indexOf(\" \")==-1");
				p.getCtrls().add(ctrl);
			}
			

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("array"))
		{
			// can not convert this to proper float or integer type.
			p.setType(ParameterType.StringType);
			if (attributes.containsKey("minimum"))
			{
				comment.getValue().add("The minimum value for each element is " + attributes.get("minimum"));
			}

			if (attributes.containsKey("maximum"))
			{
				comment.getValue().add("The maximum value for each element is " + attributes.get("maximum"));
			}
			if (attributes.containsKey("size"))
			{
				comment.getValue().add("The input string should consist of " + attributes.get("size") + " number");
			}

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("range"))
		{
			// use input file for range.
			p.setType(ParameterType.InputFileType);

			// input file can not have default value
			p.setVdef(null);
			comment.getValue().add(
					" Ranges of sequence positions as pairs of numbers with text comments. For example:" + "12      23<br/>" + "4      5       this is like 12-23, but smaller<br/>"
							+ "67      10348   interesting region");
			p.setComment(comment);
			p.getFormat().setCode("value?\" -" + name + " @\"+value:\"\"");
			if (attributes.containsKey("minlength"))
			{
				comment.getValue().add("The minimal length for a range must be " + attributes.get("minlength"));
			} else if (attributes.containsKey("size"))
			{
				comment.getValue().add("Exactly " + attributes.get("size") + "  range are needed");
			} else if (attributes.containsKey("minsize"))
			{
				comment.getValue().add("At least " + attributes.get("minsize") + " ranges are needed");
			}

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("regexp") || type.equals("pattern"))
		{
			p.setType(ParameterType.StringType);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("codon"))
		{
			p.setType(ParameterType.SingleSelectionType);
			Vlist vlist = new Vlist();
			for (Map.Entry<String, String> entry : codons.entrySet())
			{
				vlist.getLabel().add(entry.getValue());
				vlist.getValue().add(entry.getKey());
			}
			p.setVlist(vlist);
			// Individual codon inputs can set their own default names with the
			// name:
			// attribute which in the current version has the same effect as
			// setting the default: attribute.
			// name: attributes does not exist

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("cpdb"))
		{
			p.setType(ParameterType.InputFileType);
			p.setVdef(null);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("datafile"))
		{
			/*
			 * #thoretically, datafile should be a list for the end user to
			 * select a datafile from emboss #data directory. The selected
			 * datafile is restricted by name, extension and directory
			 * attributes. #however, by search emboss 4.0 acd files, I did not
			 * find any program using name, extension,directory property.
			 * #moreover, I find 1) all data file directory is $emboss data
			 * directory. 2) all file extension is .dat
			 */
			List<String> datafiles = getDataFile(attributes);
			p.setType(ParameterType.SingleSelectionType);
			Vlist vlist = new Vlist();
			for (String file : datafiles)
			{
				vlist.getLabel().add(file);
				vlist.getValue().add(file);
			}
			p.setVlist(vlist);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("infile"))
		{
			p.setType(ParameterType.InputFileType);
			p.setVdef(null);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("matrix") || type.equals("matrixf"))
		{
			/*
			 * #the value for protein attribute is determined by the automatic
			 * variable acdprotein. #so at input time, we could not decide
			 * whether a DNA or protein variable is required or not #so we list
			 * both protein and DNA matrix. #more over, we do not list default
			 * and let the emboss binary to decide default.
			 */

			p.setType(ParameterType.SingleSelectionType);
			Vlist vlist = new Vlist();
			for (Map.Entry<String, String> entry : protein_matrices.entrySet())
			{
				vlist.getLabel().add(entry.getValue());
				vlist.getValue().add(entry.getKey());
			}
			for (Map.Entry<String, String> entry : DNA_matrices.entrySet())
			{
				vlist.getLabel().add(entry.getValue());
				vlist.getValue().add(entry.getKey());
			}
			p.setVlist(vlist);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("scop"))
		{
			p.setType(ParameterType.InputFileType);
			p.setVdef(null);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("sequence") || type.equals("seqall") || type.equals("seqset") || type.equals("seqsetall"))
		{
			p.setType(ParameterType.SequenceType);
			Paragraph qualifier = getSeqinQaulifier(p, attributes);
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
				((Program) parent).get_Parameters().add(qualifier);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
				((Paragraph) parent).get_Parameters().add(qualifier);
			}
		} else if (type.equals("tree"))
		{
			p.setType(ParameterType.InputFileType);
			p.setVdef(null);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("list") || type.equals("selection"))
		{
			int max = 1;
			if (attributes.containsKey("maximum"))
			{
				max = Integer.parseInt(attributes.get("maximum"));
			}
			if (max > 1)
			{
				p.setType(ParameterType.MultipleSelectionType);
			} else
			{
				p.setType(ParameterType.SingleSelectionType);
			}
			String values = attributes.get("values");
			String delimiter = attributes.get("delimiter");
			if (delimiter == null)
			{
				delimiter = ";";
			}
			String codedelimiter = attributes.get("codedelimiter");
			if (codedelimiter == null)
			{
				codedelimiter = ":";
			}
			Vlist vlist = new Vlist();
			for (String temp : values.split(delimiter))
			{
				if (type.equals("list"))
				{
					int index = temp.indexOf(codedelimiter);
					String value = temp.substring(0, index).trim();
					String label = temp.substring(index + codedelimiter.length()).trim();
					vlist.getLabel().add(label);
					vlist.getValue().add(value);
				} else
				{
					vlist.getLabel().add(temp);
					vlist.getValue().add(temp);
				}
			}
			p.setVlist(vlist);
			if (attributes.containsKey("header"))
			{
				p.setPrompt(attributes.get("header ") + p.getPrompt());
			}

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("align"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + "_align.txt");
				p.setVdef(vdef);
			}

			Paragraph qualifier = getAlignQaulifier(p, attributes);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
				((Program) parent).get_Parameters().add(qualifier);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
				((Paragraph) parent).get_Parameters().add(qualifier);
			}

		} else if (type.equals("featout"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				String ext = attributes.get("extension");
				if (ext == null)
				{
					ext = attributes.get("offormat");
				}
				if (ext == null)
				{
					ext = "gff";
				}
				vdef.setValue("outfile" + group + "_featout." + ext);
				p.setVdef(vdef);
				

				Paragraph qualifier = getFeatoutQaulifier(p, attributes);

				if (parent instanceof Program)
				{
					((Program) parent).get_Parameters().add(p);
					((Program) parent).get_Parameters().add(qualifier);
				} else
				{
					((Paragraph) parent).get_Parameters().add(p);
					((Paragraph) parent).get_Parameters().add(qualifier);
				}
			}
		} else if (type.equals("outcodon"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + "_codon.txt");
				p.setVdef(vdef);
			}
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("outcpdb"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + "_cpdb.txt");
				p.setVdef(vdef);
			}
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("outdata"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + "_data.txt");
				p.setVdef(vdef);
			}
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("outfile"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				String ext = attributes.get("extension");
				if (ext == null)
				{
					ext = name;
				}
				vdef.setValue("outfile" + group + "." + ext);
				p.setVdef(vdef);
			}
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("outdiscrete"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + ".txt");
				p.setVdef(vdef);
			}
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("outdistance"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + ".txt");
				p.setVdef(vdef);
			}
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("outfreq"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + ".txt");
				p.setVdef(vdef);
			}
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("outmatrix"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + ".txt");
				p.setVdef(vdef);
			}
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("outmatrixf"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + ".txt");
				p.setVdef(vdef);
			}
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("outproperties"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + ".txt");
				p.setVdef(vdef);
			}
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("outscope"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + ".txt");
				p.setVdef(vdef);
			}
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("outtree"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + ".txt");
				p.setVdef(vdef);
			}
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
			}
		} else if (type.equals("report"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + ".txt");
				p.setVdef(vdef);
			}
			Paragraph qualifier = getReportQaulifier(p, attributes);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
				((Program) parent).get_Parameters().add(qualifier);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
				((Paragraph) parent).get_Parameters().add(qualifier);
			}
		} else if (type.equals("seqout") || type.equals("seqoutall") || type.equals("seqoutset"))
		{
			p.setType(ParameterType.OutputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + ".txt");
				p.setVdef(vdef);
			}
			Paragraph qualifier = getSeqoutQaulifier(p, attributes);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
				((Program) parent).get_Parameters().add(qualifier);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
				((Paragraph) parent).get_Parameters().add(qualifier);
			}
		} else if (type.equals("graph") || type.equals("xygraph"))
		{
			p.setType(ParameterType.SingleSelectionType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("png");
				p.setVdef(vdef);
			}
			Vlist vlist = new Vlist();
			vlist.getValue().add("hp7470");
			vlist.getLabel().add("hp7470");

			vlist.getValue().add("ps");
			vlist.getLabel().add("postscript");

			vlist.getValue().add("cps");
			vlist.getLabel().add("color postscript");

			vlist.getValue().add("hp7580");
			vlist.getLabel().add("hp7580");

			vlist.getValue().add("data");
			vlist.getLabel().add("data");

			vlist.getValue().add("text");
			vlist.getLabel().add("text");

			vlist.getValue().add("none");
			vlist.getLabel().add("none");

			vlist.getValue().add("hpgl");
			vlist.getLabel().add("hpgl");

			vlist.getValue().add("tekt");
			vlist.getLabel().add("tekt");

			vlist.getValue().add("meta");
			vlist.getLabel().add("meta");

			vlist.getValue().add("tek");
			vlist.getLabel().add("tek");

			vlist.getValue().add("png");
			vlist.getLabel().add("png");

			p.setVlist(vlist);
			Paragraph qualifier = getGraphQaulifier(p, attributes);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
				((Program) parent).get_Parameters().add(qualifier);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
				((Paragraph) parent).get_Parameters().add(qualifier);
			}
		} else if (type.equals("features") )
		{
			p.setType(ParameterType.InputFileType);
			if (p.getVdef() == null)
			{
				Value vdef = new Value();
				vdef.setValue("outfile" + group + ".txt");
				p.setVdef(vdef);
			}
			Paragraph qualifier = getFeaturesQaulifier(p, attributes);

			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
				((Program) parent).get_Parameters().add(qualifier);
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
				((Paragraph) parent).get_Parameters().add(qualifier);
			}
		}
		else if (type.equals("filelist") )
		{
			p.setType(ParameterType.StringType);
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
				
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
				
			}
			// default type for unsupported type to string.
			//logger.warn(type + " parameter type is found for application " + name);
		}else if (type.equals("discretestates")
				|| type.equals("properties")
				||type.equals("frequencies")
				||type.equals("distances")
				)
		{
			p.setType(ParameterType.InputFileType);
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
				
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
				
			}
		}
//		else if (type.equals("") )
//		{
//			p.setType(ParameterType.DirlistType);
//			if (parent instanceof Program)
//			{
//				((Program) parent).get_Parameters().add(p);
//				
//			} else
//			{
//				((Paragraph) parent).get_Parameters().add(p);
//				
//			}
//		}
		else
		{
			p.setType(ParameterType.StringType);
			if (parent instanceof Program)
			{
				((Program) parent).get_Parameters().add(p);
				
			} else
			{
				((Paragraph) parent).get_Parameters().add(p);
				
			}
			// default type for unsupported type to string.
			logger.warn(type + " parameter type is found for application " + name);
		}

		return group;
	}

	protected static String processAttributeValue(String value)
	{
		if (value == null)
			return value;
		value=value.trim();

		// TODO assume linebreak is \n instead of \r\n;
		if (value.charAt(0) == '"')
		{
			value = value.substring(1);
		}
		if (value.charAt(value.length() - 1) == '\n')
		{
			value = value.substring(0, value.length() - 1);
		}
		if (value.charAt(value.length() - 1) == '"')
		{
			value = value.substring(0, value.length() - 1);
		}

		// value=value.substring(1,value.length()-2);
		if (value.length() == 0)
		{
			return null;
		}
		value = value.replace("\\\"", "\"");
		value = value.replace("\\\\", "\\");
		return value;
	}

	protected static Map<String, String> processGlobalAttributes(Parameter p, CommonTree tree)
	{
		String type = tree.getChild(0).getText();
		String paramName = tree.getChild(1).getText();

		Map<String, String> attributes = collectAttributes(tree);
		Comment comment = new Comment();
		String information = attributes.get("information");
		String help = attributes.get("help");
		String prompt = attributes.get("prompt");
		String defaultvalue = attributes.get("default");
		String code = attributes.get("code");

		String parametervalue = attributes.get("parameter");
		if (parametervalue != null && parametervalue.equals("Y"))
		{
			p.setMandatory(true);
			p.setSimple(true);
		}
		String standard = attributes.get("standard");

		if (standard != null && standard.equals("Y"))
		{
			p.setMandatory(true);
		}
		if (help != null)
		{
			comment.getValue().add(help);
		}
		if (attributes.containsKey("expect"))
		{
			comment.getValue().add("Default value:" + attributes.get("expect"));

		}
		if (attributes.containsKey("valid"))
		{
			comment.getValue().add("Allowed values: " + attributes.get("valid"));
		}
		if (attributes.containsKey("comment"))
		{
			comment.getValue().add(attributes.get("comment"));
		}
		if (attributes.containsKey("needed"))
		{
			if (attributes.get("needed").equals("N"))
			{
				p.setHidden(true);
			}
		}

		if (information != null)
		{
			prompt = information;
		} else if (help != null)
		{
			prompt = help;
		} else if (prompt != null)
		{
			// nothing
		} else
		{
			String tempprompt = null;
			if (code != null)
			{
				tempprompt = codes.get(code);
			}
			if (tempprompt == null)
			{
				tempprompt = codes.get("DEF" + type.toUpperCase());
			}
			if (tempprompt == null)
			{
				tempprompt = codes.get("HELP" + type.toUpperCase());
			}
			if (tempprompt != null)
			{
				prompt = tempprompt;
			}
		}
		if (prompt != null)
		{
			p.setPrompt(prompt + "(-" + paramName + ")");
		} else
		{
			p.setPrompt("(-" + paramName + ")");
		}
		if (defaultvalue != null && isLiteralValue(defaultvalue))
		{
			Value vdef = new Value();
			vdef.setValue(defaultvalue);
			p.setVdef(vdef);
			Code format = new Code();
			format.setLanguage("javascript");
			format.setCode("(value && value!=vdef)?\" -" + paramName + " \"+value:\"\"");
			p.setFormat(format);

		} else
		{
			Code format = new Code();
			format.setLanguage("javascript");
			format.setCode("value?\" -" + paramName + " \"+value:\"\"");
			p.setFormat(format);
		}
		if (comment.getValue().size() > 0)
		{
			p.setComment(comment);
		}
		return attributes;
	}

	private static boolean isLiteralValue(String value)
	{
		if (value.indexOf('$') == -1 && value.indexOf('@') == -1)
		{
			return true;
		} else
		{
			return false;
		}
	}

	protected static Map<String, String> collectAttributes(CommonTree tree)
	{
		Map<String, String> attributes = new HashMap<String, String>();
		for (int i = 0; i < tree.getChildCount(); i++)
		{
			CommonTree child = (CommonTree) tree.getChild(i);
			if (child.getType() == AcdLexer.ATTRIBUTE)
			{
				String name = child.getChild(0).getText();
				String value=null;
				if (child.getChildCount()==2 && child.getChild(1)!=null)
				{
					value = child.getChild(1).getText();
				}
				value = processAttributeValue(value);
				if (value == null)
				{
					continue;
				}
				attributes.put(name, value);
			}
		}
		return attributes;
	}

	protected static Map<String, String> getCodes() throws IOException
	{
		String codeFile = EMBOSS_ACD + File.separator + "codes.english";
		BufferedReader reader = new BufferedReader(new FileReader(codeFile));
		Map<String, String> ret = new HashMap<String, String>();
		String line = null;
		while ((line = reader.readLine()) != null)
		{
			line = line.trim();
			if (line.length() == 0)
				continue;
			if (line.startsWith("#"))
				continue;
			int index = line.indexOf(' ');
			if (index == -1)
				continue;
			String name = line.substring(0, index);
			String value = line.substring(index).trim();
			if (value.startsWith("\""))
				value = value.substring(1);
			if (value.endsWith("\""))
				value = value.substring(0, value.length() - 1);
			ret.put(name, value);
		}
		return ret;
	}

	protected static List<String> getDataFile(Map<String, String> attributes)
	{
		String ext = attributes.get("extension");
		if (ext == null)
		{
			ext = "dat";
		}
		String directory = attributes.get("directory");
		if (directory == null)
		{
			directory = EMBOSS_DATA;
		} else
		{
			directory = EMBOSS_DATA + File.separator + directory;
		}

		File dir = new File(directory);

		return Arrays.asList(dir.list(new SuffixFileFilter("."+ext)));
	}

	public static void init() throws IOException
	{
		//do not initialize if the EMBOSS_
		File d=new File(EMBOSS_DATA);
		if (!d.exists() || !d.isDirectory())
		{
			return ;
		}
		DNA_matrices = loadMatrix(EMBOSS_DATA + File.separator + "Matrices.nucleotide");
		protein_matrices = loadMatrix(EMBOSS_DATA + File.separator + "Matrices.protein");
		proteinstructure_matrices = loadMatrix(EMBOSS_DATA + File.separator + "Matrices.proteinstructure");
		codons = loadMatrix(EMBOSS_DATA + File.separator + "CODONS" + File.separator + "Cut.index");
		codes = getCodes();

	}

	protected static Map<String, String> loadMatrix(String file) throws IOException
	{
		BufferedReader reader = new BufferedReader(new FileReader(file));
		String line = null;
		Map<String, String> ret = new HashMap<String, String>();
		while ((line = reader.readLine()) != null)
		{
			line = line.trim();
			if (line.startsWith("#"))
				continue;
			int index = line.indexOf(' ');
			if (index == -1)
				continue;
			String key = line.substring(0, index);
			String value = line.substring(index + 1);
			value = value.trim();
			ret.put(key, value);
		}
		return ret;
	}

	protected static Paragraph getAlignQaulifier(Parameter parameter, Map<String, String> attributes)
	{
		Paragraph paragraph = new Paragraph();
		paragraph.setType(ParameterType.ParagraphType);

		int group = parameter.getGroup();
		String name = parameter.getName();

		paragraph.setName(name + "_qaulifier");
		paragraph.setPrompt("control " + name + " output");
		boolean aglobal = false;
		if (attributes.containsKey("aglobal") && attributes.get("aglobal").equals("Y"))
		{
			aglobal = true;
		}
		boolean multiple = false;
		if (attributes.containsKey("multiple") && attributes.get("multiple").equals("Y"))
		{
			multiple = true;
		}
		String aformat = attributes.get("aformat");
		if (aformat == null)
		{
			aformat = multiple ? "msf" : "pair";
		}

		// aformat parameter.
		Parameter p = new Parameter();
		p.setName(name + "_aformat");
		p.setGroup(group);
		p.setType(ParameterType.SingleSelectionType);
		p.setPrompt("Alignment format(-aformat)");

		Code format = new Code();
		format.setLanguage("javascript");
		format.setCode("(value && value!=vdef)?\" -aformat \"+value:\"\"");
		p.setFormat(format);

		Vlist vlist = new Vlist();
		String formats[] = { "fasta", "msf", "srs", "trace", "simple", "multiple", "pair", "match", "markx0", "markx1", "markx2", "markx3", "markx10", "srspari", "score" };
		boolean hasaformat = false;
		for (String f : formats)
		{
			vlist.getLabel().add(f);
			vlist.getValue().add(f);
			if (f.equals(aformat))
			{
				hasaformat = true;
			}

		}
		if (!hasaformat)
		{
			vlist.getLabel().add(aformat);
			vlist.getValue().add(aformat);
		}
		p.setVlist(vlist);

		Value vdef = new Value();
		vdef.setValue(aformat);
		p.setVdef(vdef);

		paragraph.get_Parameters().add(p);

		// extension
		p = new Parameter();
		p.setType(ParameterType.StringType);
		p.setName(name + "_aextension");
		p.setGroup(group);
		p.setPrompt("Align file extension (-aextension)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -aextension \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		// awidth
		p = new Parameter();
		p.setType(ParameterType.IntegerType);
		p.setName(name + "_awidth");
		p.setGroup(group);
		p.setPrompt("Alignment width (-awidth)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -awidth \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		// show access
		p = new Parameter();
		p.setType(ParameterType.BooleanType);
		p.setName(name + "_aaccshow");
		p.setGroup(group);
		p.setPrompt("Show accession number in the header(-aaccshow)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -aaccshow \":\"\"");
		p.setFormat(format);
		vdef = new Value();
		vdef.setValue("0");
		p.setVdef(vdef);
		paragraph.get_Parameters().add(p);

		// show description
		p = new Parameter();
		p.setType(ParameterType.BooleanType);
		p.setName(name + "_adesshow");
		p.setGroup(group);
		p.setPrompt("Show description in the header(-adesshow)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -adesshow \":\"\"");
		p.setFormat(format);
		vdef = new Value();
		vdef.setValue("0");
		p.setVdef(vdef);
		paragraph.get_Parameters().add(p);

		// show USA
		p = new Parameter();
		p.setType(ParameterType.BooleanType);
		p.setName(name + "_ausashow");
		p.setGroup(group);
		p.setPrompt("Show the full USA in the alignment(-ausashow)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -ausashow \":\"\"");
		p.setFormat(format);
		vdef = new Value();
		vdef.setValue("0");
		p.setVdef(vdef);
		paragraph.get_Parameters().add(p);

		// show full sequences
		p = new Parameter();
		p.setType(ParameterType.BooleanType);
		p.setName(name + "_aglobal");
		p.setGroup(group);
		p.setPrompt("Show the full sequence in alignment(-aglobal)");
		format = new Code();
		format.setLanguage("javascript");

		if (aglobal)
		{
			format.setCode("value==0?\" -noaglobal \":\"\"");
			p.setFormat(format);
			vdef = new Value();
			vdef.setValue("1");
			p.setVdef(vdef);
		} else
		{
			format.setCode("value==1?\" -aglobal \":\"\"");
			p.setFormat(format);
			vdef = new Value();
			vdef.setValue("0");
			p.setVdef(vdef);
		}
		paragraph.get_Parameters().add(p);

		return paragraph;
	}

	protected static Paragraph getReportQaulifier(Parameter parameter, Map<String, String> attributes)
	{
		Paragraph paragraph = new Paragraph();
		paragraph.setType(ParameterType.ParagraphType);

		int group = parameter.getGroup();
		String name = parameter.getName();

		paragraph.setName(name + "_qaulifier");
		paragraph.setPrompt("control " + name + " output");

		String rformat = attributes.get("rformat");
		String rextension = attributes.get("rextension");
		if (rextension == null)
		{
			rextension = name;
		}
		boolean rscoreshow = false;
		if (attributes.containsKey("rscoreshow") && attributes.get("rscoreshow").equals("Y"))
		{
			rscoreshow = true;
		}

		// aformat parameter.
		Parameter p = new Parameter();
		p.setName(name + "_rformat");
		p.setGroup(group);
		p.setType(ParameterType.SingleSelectionType);
		p.setPrompt("Report format(-rformat)");

		Code format = new Code();
		format.setLanguage("javascript");
		if (rformat != null)
		{
			format.setCode("(value && value!=vdef)?\" -rformat \"+value:\"\"");
		} else
		{
			format.setCode("(value)?\" -rformat \"+value:\"\"");
		}
		p.setFormat(format);

		Vlist vlist = new Vlist();
		String formats[] = { "embl", "genbank", "gff", "pir", "swiss", "trace", "listfile", "dbmotif", "diffseq", "excel", "feattable", "motif", "regions", "seqtable", "simple", "srs", "table",
							"tagseq" };

		for (String f : formats)
		{
			vlist.getLabel().add(f);
			vlist.getValue().add(f);

		}
		p.setVlist(vlist);

		if (rformat != null)
		{
			Value vdef = new Value();
			vdef.setValue(rformat);
			p.setVdef(vdef);
		}
		paragraph.get_Parameters().add(p);

		// extension
		p = new Parameter();
		p.setType(ParameterType.StringType);
		p.setName(name + "_rextension");
		p.setGroup(group);
		p.setPrompt("report file name extension(-rextension)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -rextension \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		// maximal hits to report
		p = new Parameter();
		p.setType(ParameterType.IntegerType);
		p.setName(name + "_rmaxall");
		p.setGroup(group);
		p.setPrompt("Maximum total hits to report(-rmaxall)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -rmaxall \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		// maximal hits to report for one sequence
		p = new Parameter();
		p.setType(ParameterType.IntegerType);
		p.setName(name + "_rmaxseq");
		p.setGroup(group);
		p.setPrompt("Maximum hits to report for one sequence(-maxseq)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -rmaxseq \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		// show access
		p = new Parameter();
		p.setType(ParameterType.BooleanType);
		p.setName(name + "_raccshow");
		p.setGroup(group);
		p.setPrompt("Show accession number in the report(-raccshow)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -raccshow \":\"\"");
		p.setFormat(format);
		Value vdef = new Value();
		vdef.setValue("0");
		p.setVdef(vdef);
		paragraph.get_Parameters().add(p);

		// show description
		p = new Parameter();
		p.setType(ParameterType.BooleanType);
		p.setName(name + "_rdesshow");
		p.setGroup(group);
		p.setPrompt("Show description in the report(-rdesshow)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -rdesshow \":\"\"");
		p.setFormat(format);
		vdef = new Value();
		vdef.setValue("0");
		p.setVdef(vdef);
		paragraph.get_Parameters().add(p);

		// show USA
		p = new Parameter();
		p.setType(ParameterType.BooleanType);
		p.setName(name + "_rusashow");
		p.setGroup(group);
		p.setPrompt("Show the full USA in the report(-rusashow)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -rusashow \":\"\"");
		p.setFormat(format);
		vdef = new Value();
		vdef.setValue("0");
		p.setVdef(vdef);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setType(ParameterType.BooleanType);
		p.setName(name + "_rscoreshow");
		p.setGroup(group);
		p.setPrompt("Show the score in the report(-rscoreshow)");
		format = new Code();
		format.setLanguage("javascript");

		if (rscoreshow)
		{
			format.setCode("value==0?\" -norscoreshow \":\"\"");
			p.setFormat(format);
			vdef = new Value();
			vdef.setValue("1");
			p.setVdef(vdef);
		} else
		{
			format.setCode("value==1?\" -rscoreshow \":\"\"");
			p.setFormat(format);
			vdef = new Value();
			vdef.setValue("0");
			p.setVdef(vdef);
		}
		paragraph.get_Parameters().add(p);

		return paragraph;
	}

	protected static Paragraph getSeqinQaulifier(Parameter parameter, Map<String, String> attributes)
	{
		Paragraph paragraph = new Paragraph();
		paragraph.setType(ParameterType.ParagraphType);
		int group = parameter.getGroup();
		String name = parameter.getName();

		paragraph.setName(name + "_qaulifier");
		paragraph.setPrompt("control " + name + " sequence inputs");

		Parameter p = null;
		Code format = null;

		p = new Parameter();
		p.setName(name + "_sbegin");
		p.setGroup(group);
		p.setType(ParameterType.IntegerType);
		p.setPrompt("Start of each sequence to be used(-sbegin)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -sbegin \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_send");
		p.setGroup(group);
		p.setType(ParameterType.IntegerType);
		p.setPrompt("End of each sequence to be used(-send)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -send \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_sreverse");
		p.setGroup(group);
		p.setType(ParameterType.BooleanType);
		p.setPrompt("Reverse (if DNA) (-sreverse)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -sreverse \":\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_snucleotide");
		p.setGroup(group);
		p.setType(ParameterType.BooleanType);
		p.setPrompt("Sequence is nucleotide(-snucleotide)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -snucleotide \":\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_sprotein");
		p.setGroup(group);
		p.setType(ParameterType.BooleanType);
		p.setPrompt("Sequence is protein(-sprotein)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -sprotein \":\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_slower");
		p.setGroup(group);
		p.setType(ParameterType.BooleanType);
		p.setPrompt("Make lower case(-slower)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -slower \":\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_supper");
		p.setGroup(group);
		p.setType(ParameterType.BooleanType);
		p.setPrompt("Make upper case(-supper)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -supper \":\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_sformat");
		p.setGroup(group);
		p.setType(ParameterType.SingleSelectionType);
		p.setPrompt("Input sequence format(-sformat)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -sformat \"+value:\"\"");
		p.setFormat(format);
		String formats[] = { "fasta", "gcg", "phylip", "embl", "swiss", "ncbi", "nbrf", "genbank", "ig", "codata", "strider", "acedb", "staden", "text", "fitch", "msf", "clustal", "phylip",
							"phylip3", "asn1" };
		Vlist vlist = new Vlist();
		for (String f : formats)
		{
			vlist.getLabel().add(f);
			vlist.getValue().add(f);

		}
		p.setVlist(vlist);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_sdbname");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt(" Database name(-sdbname)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -sdbname \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_sid");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt(" Entryname(-sid)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -sid \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_ufo");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt(" UFO features(-ufo)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -ufo \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_fformat");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt(" Features forma(-fformat)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -fformat \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_fopenfile");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt(" Features file name(-fopenfile)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -fopenfile \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		return paragraph;
	}

	protected static Paragraph getSeqoutQaulifier(Parameter parameter, Map<String, String> attributes)
	{
		Paragraph paragraph = new Paragraph();
		paragraph.setType(ParameterType.ParagraphType);
		int group = parameter.getGroup();
		String name = parameter.getName();

		paragraph.setName(name + "_qaulifier");
		paragraph.setPrompt("control " + name + " output");

		Parameter p = new Parameter();
		p.setName(name + "_osformat");
		p.setGroup(group);
		p.setType(ParameterType.SingleSelectionType);
		p.setPrompt("output sequence format(-osformat))");

		Code format = new Code();
		format.setLanguage("javascript");
		format.setCode("(value && value!=vdef)?\" -osformat \"+value:\"\"");
		p.setFormat(format);

		String formats[] = { "fasta", "gcg", "phylip", "embl", "swiss", "ncbi", "nbrf", "genbank", "ig", "codata", "strider", "acedb", "staden", "text", "fitch", "msf", "clustal", "phylip",
							"phylip3", "asn1" };
		Vlist vlist = new Vlist();
		for (String f : formats)
		{
			vlist.getLabel().add(f);
			vlist.getValue().add(f);

		}
		p.setVlist(vlist);
		Value vdef = new Value();
		vdef.setValue("fasta");
		p.setVdef(vdef);
		paragraph.get_Parameters().add(p);

		// extension
		p = new Parameter();
		p.setType(ParameterType.StringType);
		p.setName(name + "_osextension");
		p.setGroup(group);
		p.setPrompt("output file name extension(-osextension)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -osextension \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		// dbname
		p = new Parameter();
		p.setType(ParameterType.StringType);
		p.setName(name + "_osdbname");
		p.setGroup(group);
		p.setPrompt("Database name to add(-osdbname)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -osdbname \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setType(ParameterType.BooleanType);
		p.setName(name + "_ossignle");
		p.setGroup(group);
		p.setPrompt("Separate file for each entry(-ossingle)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -ossingle \":\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setType(ParameterType.StringType);
		p.setName(name + "_oufo");
		p.setGroup(group);
		p.setPrompt(" UFO features(-oufo)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -oufo \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setType(ParameterType.StringType);
		p.setName(name + "_offormat");
		p.setGroup(group);
		p.setPrompt(" UFO features format(-offormat)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -offormat \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setType(ParameterType.StringType);
		p.setName(name + "_ofname");
		p.setGroup(group);
		p.setPrompt("  Features file name(-ofname)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -ofname \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		return paragraph;
	}

	protected static Paragraph getFeatoutQaulifier(Parameter parameter, Map<String, String> attributes)
	{
		Paragraph paragraph = new Paragraph();
		paragraph.setType(ParameterType.ParagraphType);
		int group = parameter.getGroup();
		String name = parameter.getName();

		paragraph.setName(name + "_qaulifier");
		paragraph.setPrompt("control " + name + " feature output");

		Parameter p = null;
		Code format = null;
		
		p = new Parameter();
		p.setName(name + "_offormat");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt("output feature format(-offormat))");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -offormat \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);
		
		// extension
		p = new Parameter();
		p.setType(ParameterType.StringType);
		p.setName(name + "_ofextension");
		p.setGroup(group);
		p.setPrompt("file name extension(-ofextension)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -ofextension \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		

		p = new Parameter();
		p.setType(ParameterType.BooleanType);
		p.setName(name + "_ofsignle");
		p.setGroup(group);
		p.setPrompt("Separate file for each entry(-ofsingle)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -ofsingle \":\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setType(ParameterType.StringType);
		p.setName(name + "_ofname");
		p.setGroup(group);
		p.setPrompt("  Features file name(-ofname)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -ofname \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		return paragraph;
	}

	
	protected static Paragraph getFeaturesQaulifier(Parameter parameter, Map<String, String> attributes)
	{
		Paragraph paragraph = new Paragraph();
		paragraph.setType(ParameterType.ParagraphType);
		int group = parameter.getGroup();
		String name = parameter.getName();

		paragraph.setName(name + "_qaulifier");
		paragraph.setPrompt("control " + name + " features");

		Parameter p = null;
		Code format = null;
		
		p = new Parameter();
		p.setName(name + "_fformat");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt("Features format(-fformat)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -fformat \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);
		
		p = new Parameter();
		p.setName(name + "_fopenfile");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt("Features open file(-fopenfile)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -fformat \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_fbegin");
		p.setGroup(group);
		p.setType(ParameterType.IntegerType);
		p.setPrompt("Start of the feature to be used(-fbegin)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -fbegin \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_fend");
		p.setGroup(group);
		p.setType(ParameterType.IntegerType);
		p.setPrompt("End of the feature to be used(-fend)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -fend \"+value:\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_freverse");
		p.setGroup(group);
		p.setType(ParameterType.BooleanType);
		p.setPrompt("Reverse (if DNA) (-freverse)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value==1?\" -freverse \":\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		return paragraph;
	}

	protected static Paragraph getGraphQaulifier(Parameter parameter, Map<String, String> attributes)
	{
		Paragraph paragraph = new Paragraph();
		paragraph.setType(ParameterType.ParagraphType);
		int group = parameter.getGroup();
		String name = parameter.getName();

		paragraph.setName(name + "_qaulifier");
		paragraph.setPrompt("control " + name + " output");

		// goutfile
		Parameter p = new Parameter();
		p.setName(name + "_goutfile");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt("graph outfile name(-goutfile)");
		Code format = new Code();
		format.setLanguage("javascript");
		format.setCode("\"-goutfile \"+value");
		p.setFormat(format);
		Value vdef = new Value();
		vdef.setValue("goutfile" + group);
		p.setVdef(vdef);
		paragraph.get_Parameters().add(p);

		String gdesc = attributes.get("gdesc");
		p = new Parameter();
		p.setName(name + "_gdesc");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt("graph description (-gdesc)");
		if (gdesc != null)
		{
			format = new Code();
			format.setLanguage("javascript");
			format.setCode("(value && value!=vdef)?\" -gdesc '\"+value+\"'\":\"\"");
			p.setFormat(format);
			vdef = new Value();
			vdef.setValue(gdesc);
			p.setVdef(vdef);
		} else
		{
			format = new Code();
			format.setLanguage("javascript");
			format.setCode("value?\" -gdesc '\"+value+\"'\":\"\"");
			p.setFormat(format);
		}
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_gtitle");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt("graph title(-gtitle)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -gtitle '\"+value+\"'\":\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_gsubtitle");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt("graph sub title(-gsubtitle)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -gsubtitle '\"+value+\"'\":\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_gxtitle");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt("graph x-aixs title (gxtitle)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -gxtitle '\"+value+\"'\":\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		p = new Parameter();
		p.setName(name + "_gytitle");
		p.setGroup(group);
		p.setType(ParameterType.StringType);
		p.setPrompt("graph y-axis title(gytitle)");
		format = new Code();
		format.setLanguage("javascript");
		format.setCode("value?\" -gytitle '\"+value+\"'\":\"\"");
		p.setFormat(format);
		paragraph.get_Parameters().add(p);

		return paragraph;
	}

	private static boolean isReserverdWord(String name)
	{
		String words[] = { "print" };
		for (String word : words)
		{
			if (word.equals(name))
			{
				return true;
			}
		}
		return false;

	}
}
